local lp = game.Players.LocalPlayer
local Workspace = game:GetService("Workspace")
local charactersFolder = Workspace:WaitForChild("Characters")

local TARGET_ANIMS = {
    'Slash',
    'Swing',
    'Sword'
}

local IGNORED_ANIMS = {
    'Equip',
    'idle',
    'Parry'
}

local animationCache = {}

local function getAnimationInfo(animId)
    if animationCache[animId] then
        return animationCache[animId]
    end
    
    local numericId = tonumber(animId:match("%d+"))
    if not numericId then
        animationCache[animId] = {Name = "InvalidID"}
        return animationCache[animId]
    end
    
    local success, info = pcall(function()
        return game:GetService("MarketplaceService"):GetProductInfo(numericId)
    end)
    
    if success then
        animationCache[animId] = info
        return info
    else
        animationCache[animId] = {Name = "Unknown"}
        return animationCache[animId]
    end
end

local function performBlock()
    pcall(function()
        keypress(0x46)
        wait()
        keyrelease(0x46)
    end)
end

local function isIgnoredAnimation(animName)
    if not animName then return false end
    local lowerName = string.lower(animName)
    
    for _, ignored in ipairs(IGNORED_ANIMS) do
        if string.find(lowerName, string.lower(ignored)) then
            return true
        end
    end
    return false
end

local function isTargetAnimation(animName)
    if not animName then return false end
    local lowerName = string.lower(animName)
    
    for _, target in ipairs(TARGET_ANIMS) do
        if string.find(lowerName, string.lower(target)) then
            return true
        end
    end
    return false
end

local function setupAnimationListener(char)
    if not char or not char:IsDescendantOf(game) then
        return
    end
    
    local humanoid = char:FindFirstChildOfClass("Humanoid")
    if not humanoid then
        return
    end
    
    humanoid.AnimationPlayed:Connect(function(track)
        if not track or not track.Animation then
            return
        end
        
        local animId = track.Animation.AnimationId
        local animInfo = getAnimationInfo(animId)
        local animName = animInfo.Name
        
        if isIgnoredAnimation(animName) then
            return
        end
        
        if not isTargetAnimation(animName) then
            return
        end
        
        local localChar = charactersFolder:FindFirstChild(lp.Name)
        if not localChar then
            return
        end
        
        local localHead = localChar:FindFirstChild("Head")
        local targetHead = char:FindFirstChild("Head")
        if not (localHead and targetHead) then
            return
        end
        
        local distance = (localHead.Position - targetHead.Position).Magnitude
        if distance <= 16 then ---distance
            performBlock()
        end
    end)
end

local function onCharacterAdded(char)
    if char then
        setupAnimationListener(char)
    end
end

local function onPlayerAdded(player)
    if player == lp then return end
    
    local existingChar = charactersFolder:FindFirstChild(player.Name)
    if existingChar then
        onCharacterAdded(existingChar)
    end
    
    player.CharacterAdded:Connect(function()
        local char = charactersFolder:WaitForChild(player.Name, 10)
        if char then
            onCharacterAdded(char)
        end
    end)
end

for _, player in ipairs(game.Players:GetPlayers()) do
    if player ~= lp then
        onPlayerAdded(player)
    end
end

game.Players.PlayerAdded:Connect(onPlayerAdded)